package grpc

import (
	"TODecider/src/logger"
	"TODecider/src/pb"
	"TODecider/src/to"
	"context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	"net"
	"time"
)

type (
	server struct{}
	Task   struct {
		basic   []*pb.Basic
		latency []*pb.Latency
		signal  chan error
	}
)

const (
	Method = "tcp"
)

var (
	coldDownPeriod time.Duration
	tasks          []Task
	log            = logger.GetLogger()
)

func (s *server) SendMsgTSTD(_ context.Context, in *pb.ToTD) (*pb.BackTS, error) {
	var t Task
	t.basic = in.Basic
	t.latency = in.Latency
	t.signal = make(chan error, 0)
	tasks = append(tasks, t)
	err := <-t.signal
	if err != nil {
		return nil, err
	}
	res := pb.BackTS{
		Basic:   t.basic,
		Latency: t.latency,
	}
	return &res, nil
}

func TO(task []Task) {
	if len(task) != 0 {
		var taskInBasic []*pb.Basic
		var taskInLatency []*pb.Latency
		for _, t := range task {
			taskInBasic = append(taskInBasic, t.basic...)
			taskInLatency = append(taskInLatency, t.latency...)
		}
		log.Debugf("[gRPC TD] concurrent with number: %d!", len(taskInBasic))
		err := to.Execute(taskInBasic, taskInLatency)
		if err != nil {
			log.Errorf("[gRPC TD] error: %v", err)
		}
		for _, b0 := range task {
			b0.signal <- err
		}
	}
}

func StartGrpcServer(serverSocket string, cold int) {
	coldDownPeriod = time.Millisecond * time.Duration(cold)
	// listening network port
	listener, err := net.Listen(Method, serverSocket)
	if err != nil {
		log.Fatalf("[gRPC TD] failed to listen to socket %s: %v", serverSocket, err)
	}
	// initialize StartSlot
	go StartSlot()
	// open gRPC service
	s := grpc.NewServer()
	pb.RegisterSendMsgTSTDServer(s, &server{})
	reflection.Register(s)
	log.Info("[gRPC TD] started successfully")
	err = s.Serve(listener)
	if err != nil {
		log.Fatalf("[gRPC TD] failed to start server: ", err)
	}
}

func StartSlot() {
	ticker := time.NewTicker(coldDownPeriod)
	for {
		<-ticker.C
		var t = tasks
		var tNew []Task
		tasks = tNew
		go TO(t)
	}
}
